package com.icongyou.enterprise.talent_marking.service.impl;

import com.icongyou.enterprise.common.result.Result;
import com.icongyou.enterprise.data_aggregation.mapper.DataAggregationMapper;
import com.icongyou.enterprise.talent_marking.entity.PerformanceChanges;
import com.icongyou.enterprise.talent_marking.entity.vo.ChangeDetailVO;
import com.icongyou.enterprise.talent_marking.mapper.PerformanceChangeMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("绩效变化服务测试")
class PerformanceChangesServiceImplTest {

    @Mock
    private PerformanceChangeMapper changesMapper;

    @Mock
    private DataAggregationMapper dataAggregationMapper;

    @InjectMocks
    private PerformanceChangesServiceImpl performanceChangesService;

    private PerformanceChanges change1;
    private PerformanceChanges change2;
    private PerformanceChanges change3;

    @BeforeEach
    void setUp() {
        // 学生1的变化记录
        change1 = new PerformanceChanges();
        change1.setId("CHANGE001");
        change1.setStudentId("STUDENT001");
        change1.setCourseId("COURSE001");
        change1.setCourseName("Java编程");
        change1.setChangeType("成绩变化");
        change1.setChangeDescription("课程总分从 80 分变为 85 分");
        change1.setDetectedTime(new Date());

        // 学生1的另一个变化
        change2 = new PerformanceChanges();
        change2.setId("CHANGE002");
        change2.setStudentId("STUDENT001");
        change2.setCourseId("COURSE002");
        change2.setCourseName("数据结构");
        change2.setChangeType("排名变化");
        change2.setChangeDescription("课程排名从第 15 名变为第 10 名");
        change2.setDetectedTime(new Date());

        // 学生2的变化
        change3 = new PerformanceChanges();
        change3.setId("CHANGE003");
        change3.setStudentId("STUDENT002");
        change3.setCourseId("COURSE001");
        change3.setCourseName("Java编程");
        change3.setChangeType("进度变化");
        change3.setChangeDescription("完成任务数从 5 个变为 7 个");
        change3.setDetectedTime(new Date());
    }

    // ==================== getRecentChanges 测试 ====================

    @Test
    @DisplayName("获取最近变化 - 有多个学生的变化")
    void testGetRecentChanges_WithMultipleStudents() {
        // Arrange
        List<PerformanceChanges> changes = Arrays.asList(change1, change2, change3);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001")).thenReturn("张三");
        when(dataAggregationMapper.selectRealNameById("STUDENT002")).thenReturn("李四");

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        assertNotNull(result.getData());
        
        List<ChangeDetailVO> detailList = result.getData();
        assertEquals(2, detailList.size()); // 2个学生

        // 验证学生1的变化（有2个）
        ChangeDetailVO student1Details = detailList.stream()
                .filter(d -> "STUDENT001".equals(d.getStudentId()))
                .findFirst()
                .orElse(null);
        assertNotNull(student1Details);
        assertEquals("张三", student1Details.getStudentName());
        assertEquals(2, student1Details.getChanges().size());

        // 验证学生2的变化（有1个）
        ChangeDetailVO student2Details = detailList.stream()
                .filter(d -> "STUDENT002".equals(d.getStudentId()))
                .findFirst()
                .orElse(null);
        assertNotNull(student2Details);
        assertEquals("李四", student2Details.getStudentName());
        assertEquals(1, student2Details.getChanges().size());

        verify(changesMapper).selectRecentChanges(any(LocalDate.class));
        verify(dataAggregationMapper, times(2)).selectRealNameById("STUDENT001");
        verify(dataAggregationMapper, times(1)).selectRealNameById("STUDENT002");
    }

    @Test
    @DisplayName("获取最近变化 - 单个学生多个变化")
    void testGetRecentChanges_SingleStudentMultipleChanges() {
        // Arrange
        List<PerformanceChanges> changes = Arrays.asList(change1, change2);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001")).thenReturn("张三");

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        List<ChangeDetailVO> detailList = result.getData();
        assertEquals(1, detailList.size());

        ChangeDetailVO details = detailList.get(0);
        assertEquals("STUDENT001", details.getStudentId());
        assertEquals("张三", details.getStudentName());
        assertEquals(2, details.getChanges().size());
        assertNotNull(details.getLatestChangeTime());

        verify(changesMapper).selectRecentChanges(any(LocalDate.class));
        verify(dataAggregationMapper, times(2)).selectRealNameById("STUDENT001");
    }

    @Test
    @DisplayName("获取最近变化 - 空列表")
    void testGetRecentChanges_EmptyList() {
        // Arrange
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(Collections.emptyList());

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        assertEquals("发现0个课程的变化", result.getMessage());
        assertNotNull(result.getData());
        assertTrue(result.getData().isEmpty());

        verify(changesMapper).selectRecentChanges(any(LocalDate.class));
        verify(dataAggregationMapper, never()).selectRealNameById(anyString());
    }

    @Test
    @DisplayName("获取最近变化 - 学生姓名查询失败")
    void testGetRecentChanges_StudentNameQueryFails() {
        // Arrange
        List<PerformanceChanges> changes = Arrays.asList(change1);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001"))
                .thenThrow(new RuntimeException("Database error"));

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        List<ChangeDetailVO> detailList = result.getData();
        assertEquals(1, detailList.size());
        assertEquals("未知学生", detailList.get(0).getStudentName());

        verify(changesMapper).selectRecentChanges(any(LocalDate.class));
        verify(dataAggregationMapper).selectRealNameById("STUDENT001");
    }

    @Test
    @DisplayName("获取最近变化 - 验证时间范围（最近7天）")
    void testGetRecentChanges_VerifyDateRange() {
        // Arrange
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(Collections.emptyList());

        LocalDate expectedDate = LocalDate.now().minusDays(7);

        // Act
        performanceChangesService.getRecentChanges();

        // Assert
        verify(changesMapper).selectRecentChanges(argThat(date -> 
            date.equals(expectedDate)
        ));
    }

    @Test
    @DisplayName("获取最近变化 - 验证变化项完整性")
    void testGetRecentChanges_VerifyChangeItemCompleteness() {
        // Arrange
        List<PerformanceChanges> changes = Arrays.asList(change1);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001")).thenReturn("张三");

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        ChangeDetailVO detail = result.getData().get(0);
        assertEquals(1, detail.getChanges().size());

        var changeItem = detail.getChanges().get(0);
        assertEquals("COURSE001", changeItem.getCourseId());
        assertEquals("Java编程", changeItem.getCourseName());
        assertEquals("成绩变化", changeItem.getChangeType());
        assertEquals("课程总分从 80 分变为 85 分", changeItem.getChangeDescription());
        assertNotNull(changeItem.getDetectedTime());
    }

    @Test
    @DisplayName("获取最近变化 - 同一学生相同课程的多个变化")
    void testGetRecentChanges_SameStudentSameCourseMultipleChanges() {
        // Arrange
        PerformanceChanges change1a = new PerformanceChanges();
        change1a.setId("CHANGE001");
        change1a.setStudentId("STUDENT001");
        change1a.setCourseId("COURSE001");
        change1a.setCourseName("Java编程");
        change1a.setChangeType("成绩变化");
        change1a.setChangeDescription("从80分变为85分");
        change1a.setDetectedTime(new Date());

        PerformanceChanges change1b = new PerformanceChanges();
        change1b.setId("CHANGE002");
        change1b.setStudentId("STUDENT001");
        change1b.setCourseId("COURSE001");
        change1b.setCourseName("Java编程");
        change1b.setChangeType("排名变化");
        change1b.setChangeDescription("从第10名变为第8名");
        change1b.setDetectedTime(new Date());

        List<PerformanceChanges> changes = Arrays.asList(change1a, change1b);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001")).thenReturn("张三");

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(1, result.getData().size());
        ChangeDetailVO detail = result.getData().get(0);
        assertEquals(2, detail.getChanges().size());
    }

    @Test
    @DisplayName("获取最近变化 - 学生姓名为null")
    void testGetRecentChanges_StudentNameNull() {
        // Arrange
        List<PerformanceChanges> changes = Arrays.asList(change1);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001")).thenReturn(null);

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(200, result.getCode());
        List<ChangeDetailVO> detailList = result.getData();
        assertEquals(1, detailList.size());
        assertNull(detailList.get(0).getStudentName());
    }

    @Test
    @DisplayName("获取最近变化 - 验证分组逻辑")
    void testGetRecentChanges_VerifyGroupingLogic() {
        // Arrange
        PerformanceChanges s1c1 = createChange("C1", "STUDENT001", "COURSE001", "Java", "变化1");
        PerformanceChanges s1c2 = createChange("C2", "STUDENT001", "COURSE002", "Python", "变化2");
        PerformanceChanges s2c1 = createChange("C3", "STUDENT002", "COURSE001", "Java", "变化3");

        List<PerformanceChanges> changes = Arrays.asList(s1c1, s1c2, s2c1);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById("STUDENT001")).thenReturn("学生1");
        when(dataAggregationMapper.selectRealNameById("STUDENT002")).thenReturn("学生2");

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertEquals(2, result.getData().size());
        
        // 验证学生1有2个变化
        ChangeDetailVO s1Detail = result.getData().stream()
                .filter(d -> "STUDENT001".equals(d.getStudentId()))
                .findFirst()
                .orElse(null);
        assertNotNull(s1Detail);
        assertEquals(2, s1Detail.getChanges().size());

        // 验证学生2有1个变化
        ChangeDetailVO s2Detail = result.getData().stream()
                .filter(d -> "STUDENT002".equals(d.getStudentId()))
                .findFirst()
                .orElse(null);
        assertNotNull(s2Detail);
        assertEquals(1, s2Detail.getChanges().size());
    }

    @Test
    @DisplayName("获取最近变化 - 消息格式正确")
    void testGetRecentChanges_MessageFormat() {
        // Arrange
        List<PerformanceChanges> changes = Arrays.asList(change1, change2, change3);
        when(changesMapper.selectRecentChanges(any(LocalDate.class))).thenReturn(changes);
        when(dataAggregationMapper.selectRealNameById(anyString())).thenReturn("测试");

        // Act
        Result<List<ChangeDetailVO>> result = performanceChangesService.getRecentChanges();

        // Assert
        assertTrue(result.getMessage().contains("发现"));
        assertTrue(result.getMessage().contains("课程的变化"));
    }

    // ==================== 辅助方法 ====================

    private PerformanceChanges createChange(String id, String studentId, String courseId, 
                                           String courseName, String description) {
        PerformanceChanges change = new PerformanceChanges();
        change.setId(id);
        change.setStudentId(studentId);
        change.setCourseId(courseId);
        change.setCourseName(courseName);
        change.setChangeType("测试变化");
        change.setChangeDescription(description);
        change.setDetectedTime(new Date());
        return change;
    }
}
